//
// Created by Hoyin on 2024/4/19.
//

#ifndef VISUAL_LOCATION_OBJECTMATCHER_H
#define VISUAL_LOCATION_OBJECTMATCHER_H

#define BLOCK_DEPRECATED true
#define ENABLE_IMG_LOG false
#define ENABLE_TXT_LOG false

#include "yolo.h"
#include "utils.h"
#include <Eigen/Core>
#include <random>

typedef Output YOLOBox;

class ObjectMatcher {
private:
	Yolov5 _yolo;
	cv::dnn::Net _net;
	bool _yoloOK;

#if defined(BLOCK_DEPRECATED) && BLOCK_DEPRECATED == false
	static void _calcHistogram(const cv::Mat& src, std::vector<double> &convCore, int convStep, std::vector<int> &featureVector);

	static void _calcHistogram(const cv::Mat &src, cv::Mat &dstHist);

	static void _calcFeatureVectors(cv::Mat &src, std::vector<YOLOBox> &srcBoxes,
	                                std::vector<double> &convCore, int convStep,
	                                std::vector<Eigen::VectorXi> &featureVectors);
#endif

	/**
	 * 计算两幅图像的亮度差异，三通道分别作差，差值较小则说明图像相似
	 * @param src1
	 * @param src2
	 * @return
	 */
	static double _calcDifference(const cv::Mat& src1, const cv::Mat& src2);

public:
	/**
	 * 构造函数
	 * @param yoloModel 适用于YOLOv5的onnx模型文件的路径
	 * @param withCUDA
	 */
	ObjectMatcher(std::string &yoloModel, bool withCUDA=false) {
		if(!_yolo.readModel(_net, yoloModel, withCUDA)) {
			std::cerr << "Read YOLO Model at " << yoloModel << " failed." << std::endl;
			return;
		} else {
			_yoloOK = true;
		}
	}

	/**
	 * 基于YOLOv5对图像中的对象进行识别提取
	 * @param src 输入图像
	 * @param yoloResult 输出对象的外接矩形和类别
	 */
	void detect(cv::Mat &src, std::vector<YOLOBox> &yoloResult);

	/**
	 * 对双像的YOLO识别结果进行匹配
	 * 迭代 queryField 中的所有 queryBox：
	 * 		对于每个 queryBox, 迭代 endField 中的所有 endBox, 计算它们的像素强度差异和位置差异计入得分
	 * 		得分最低的 endBox 则为与当前 queryBox 最为接近的 box
	 * @param queryField 待匹配池
	 * @param endField 匹配池
	 * @param queryBoxes 待匹配对象 ROI
	 * @param endBoxes 用于匹配的 ROI
	 * @param matchMap 输出的匹配映射
	 */
	void match(cv::Mat &queryField, cv::Mat &endField, std::vector<YOLOBox> &queryBoxes, std::vector<YOLOBox> &endBoxes,
			   std::vector<std::pair<int, int>> &matchMap);

	void detectAndMatch(cv::Mat &image1, cv::Mat &image2, std::vector<YOLOBox> &yoloBoxes1,
	                    std::vector<YOLOBox> &yoloBoxes2, std::vector<std::pair<int, int>> &matchMap);

#if defined(BLOCK_DEPRECATED) && BLOCK_DEPRECATED == false
	/**
	 * 误匹配明显，已弃用
	 * @param endField
	 * @param queryField
	 * @param endBoxes
	 * @param queryBoxes
	 */
	void match_deprecated(cv::Mat &endField, cv::Mat &queryField, std::vector<YOLOBox> &endBoxes, std::vector<YOLOBox> &queryBoxes);
#endif

#if defined(BLOCK_DEPRECATED) && BLOCK_DEPRECATED == false
	/**
	 * 误匹配明显，已弃用
	 * @param endField
	 * @param queryField
	 * @param endBoxes
	 * @param queryBoxes
	 */
	void match_defaultHist(cv::Mat &endField, cv::Mat &queryField, std::vector<YOLOBox> &endBoxes, std::vector<YOLOBox> &queryBoxes);
#endif

};


#endif //VISUAL_LOCATION_OBJECTMATCHER_H
